\bibliographystyle{gbt7714-2005}

\chapter{Git简明教程}

本教程的首要目的，是使读者能用Git这个最流行的分布式版本控制系统管理自己的项目。本教程的另外一个目的，是让选修《PHP网站开发》课程的同学能通过Git工具轻松获取课程的相关文件（代码、教案等）。

本教程并不能使你成为Git工具的专家，很多高级命令并不涉及，如果想进一步学习，请阅读\href{http://git-scm.com/book/zh}{《pro git》}\cite{Scott，2009}。

\section{为什么要用Git}

\subsection{什么是版本控制}
什么是版本控制？我为什么要关心它呢？版本控制是一种记录一个或若干文件内容变化，以便将来查阅特定版本修订情况的系统。在本书所展示的例子中，我们仅对保存着软件源代码的文本文件作版本控制管理，但实际上，你可以对任何类型的文件进行版本控制。

如果你是位图形或网页设计师，可能会需要保存某一幅图片或页面布局文件的所有修订版本（这或许是你非常渴望拥有的功能）。采用版本控制系统（VCS）是个明智的选择。有了它你就可以将某个文件回溯到之前的状态，甚至将整个项目都回退到过去某个时间点的状态。你可以比较文件的变化细节，查出最后是谁修改了哪个地方，从而找出导致怪异问题出现的原因，又是谁在何时报告了某个功能缺陷等等。

使用版本控制系统通常还意味着，就算你乱来一气把整个项目中的文件改的改删的删，你也照样可以轻松恢复到原先的样子。但额外增加的工作量却微乎其微。

\subsection{三种类型的版本控制系统}

\subsubsection{本地版本控制系统}
为了解决上面提到的问题，人们很久以前就开发了许多种本地版本控制系统，大多都是采用某种简单的数据库来记录文件的历次更新差异。

其中最流行的一种叫做 rcs，现今许多计算机系统上都还看得到它的踪影。甚至在流行的 Mac OS X 系统上安装了开发者工具包之后，也可以使用 rcs 命令。它的工作原理基本上就是保存并管理文件补丁（patch）。文件补丁是一种特定格式的文本文件，记录着对应文件修订前后的内容变化。所以，根据每次修订后的补丁，rcs 可以通过不断打补丁，计算出各个版本的文件内容。

\subsubsection{集中化的版本控制系统}
接下来人们又遇到一个问题，如何让在不同系统上的开发者协同工作？于是，集中化的版本控制系统（ Centralized Version Control Systems，简称 CVCS ）应运而生。这类系统，诸如 CVS，Subversion 以及 Perforce 等，都有一个单一的集中管理的服务器，保存所有文件的修订版本，而协同工作的人们都通过客户端连到这台服务器，取出最新的文件或者提交更新。多年以来，这已成为版本控制系统的标准做法。

事分两面，有好有坏。这么做最显而易见的缺点是中央服务器的单点故障。如果宕机一小时，那么在这一小时内，谁都无法提交更新，也就无法协同工作。要是中央服务器的磁盘发生故障，碰巧没做备份，或者备份不够及时，就会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录，而被客户端偶然提取出来的保存在本地的某些快照数据就成了恢复数据的希望。但这样的话依然是个问题，你不能保证所有的数据都已经有人事先完整提取出来过。本地版本控制系统也存在类似问题，只要整个项目的历史记录被保存在单一位置，就有丢失所有历史更新记录的风险。

\subsubsection{分布式版本控制系统}
于是分布式版本控制系统（ Distributed Version Control System，简称 DVCS ）面世了。在这类系统中，像 Git，Mercurial，Bazaar 以及 Darcs 等，客户端并不只提取最新版本的文件快照，而是把代码仓库完整地镜像下来。这么一来，任何一处协同工作用的服务器发生故障，事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作，实际上都是一次对代码仓库的完整备份。

\subsection{Git简史}
同生活中的许多伟大事件一样，Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上（1991－2002年间）。到 2002 年，整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码。

到了 2005 年，开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束，他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区（特别是 Linux 的缔造者 Linus Torvalds ）不得不吸取教训，只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。他们对新的系统制订了若干目标：
\begin{itemize}
	\item 速度
	\item 简单的设计
	\item 对非线性开发模式的强力支持（允许上千个并行开发的分支）
	\item 完全分布式
	\item 有能力高效管理类似 Linux 内核一样的超大规模项目（速度和数据量）
\end{itemize}

于是Linus花了两周时间自己用C写了一个分布式版本控制系统，这就是Git。一个月之内，Linux系统的源码已经由Git管理了！什么是大牛？大家可以体会一下。\cite{廖雪峰，2014}

自诞生于 2005 年以来，Git 日臻成熟完善，在高度易用的同时，仍然保留着初期设定的目标。它的速度飞快，极其适合管理大项目，它还有着令人难以置信的非线性分支管理系统，可以应付各种复杂的项目开发需求。

Git迅速成为最流行的分布式版本控制系统，尤其是2008年，GitHub网站上线了，它为开源项目免费提供Git存储，无数开源项目开始迁移至GitHub，包括Linux\footnote{\url{https://github.com/torvalds/linux}，由大神Linux Torvalds管理。}，jQuery，PHP，Ruby等等。

历史就是这么偶然，如果不是当年BitMover公司威胁Linux社区，可能现在我们就没有免费而超级好用的Git了。

\section{在Windows中安装Git}
在 Windows 上安装 Git 非常简单，可以到 \href{http://msysgit.github.io/}{GitHub 的 msysGit 项目}下载 exe 安装文件并安装。

完成安装之后，就可以使用命令行的 Git 工具（已经自带了 ssh 客户端）了，另外还有一个图形界面的 Git 项目管理工具。

\section{用Git获取代码}
获取已有项目的内容，分为两种情况，即首次获取和更新数据。

\subsection{首次获取代码}
第一次获取已有项目数据的并不复杂，首先在想要保存项目代码的文件夹上按右键，选择Git Bash，进入Git命令行。见图\ref{fig:GItBash}：

\begin{figure}
	\centering
	\includegraphics{raw/GitBash.jpg}
	\caption{利用右键进入Git Bash}
	\label{fig:GItBash}
\end{figure}

然后在命令行中执行以下命令，即可获得托管在远程网站中的项目文件（包括代码和版本仓库），如：

\begin{lstlisting}
git clone https://git.oschina.net/yangjh/LearningPHP.git
\end{lstlisting}

其中第二个参数（https://git.oschina.net/yangjh/LearningPHP.git）就是公布在托管网站中的项目地址。上述命令执行完后，用户将得到《PHP网站开发》公选课的所有项目文件。

\subsection{获取远程仓库的更新代码}
在完成了对项目仓库的首次克隆后，想要获取项目的最新代码，只需在Git Bash命令行中执行如下操作：

\begin{lstlisting}
git pull
\end{lstlisting}

\section{用Git管理自己的项目代码}
使用Git管理自己的项目代码，也分为两种情况，首次建立仓库和提交更新内容。
\subsection{首次建立Git仓库}
\begin{enumerate}
	\item 初始化本地项目。在相应项目的文件夹上按右键，选择Git Init here。
	\item 在项目文件夹上按右键，选择Git add all files now，将文件夹中的所有文件添加到本地仓库中。
	\item 在项目文件夹上按右键，选择Git commit tool，在随后弹出的对话框中输入更新说明，提交。
	\item 如果想对本地仓库建立远程的镜像，即将本地仓库托管到github之类的站点，应先到此类站点注册帐号，建立远程仓库，然后执行如下命令建立本地仓库和远程仓库的对应关系：
	\begin{lstlisting}
	git add remote origin https://仓库地址
	\end{lstlisting}
	\item 推送本地仓库数据到远程仓库，执行如下命令：
	\begin{lstlisting}
	git push -u origin master
	\end{lstlisting}

	然后输入用户名和密码即可完成推送。
\end{enumerate}

\subsection{提交更新内容}
完成上述操作后，以后的工作流程就更简洁了：
\begin{enumerate}
	\item 编写或者修改代码，保存文件。
	\item 添加更新文件到本地仓库，选择Git add all files now即可。
	\item 选择Git commit tool为这些更新添加说明注释。
	\item 执行Git push将本地仓库同步到远程仓库。
\end{enumerate}

至此，我们已经能用Git工具来管理和追踪项目的变化了，enjoy Git!

\section{Git进阶}
初学者可先不阅读这一节内容，在有需求的时候再深入学习。

\subsection{忽略项目中的特定文件}
在项目中，总会有一些特定的文件不想采用Git工具进行版本的控制，如临时文件、编译时产生的过渡文件或包含帐号信息的文件，对于这类文件，Git提供了一个非常高效灵活的方式进行屏蔽，即创建一个.gitignore文件。

在这个文件中，项目拥有者只需将不想进入版本仓库的文件列举出来即可，支持通配符。例如：

\begin{lstlisting}
*.sublime-project
*.sublime-workspace
*.bak
*.dump
.gz(busy)
test/*
\end{lstlisting}

需要提醒的是，当项目管理人员改变了.gitignore文件的内容后，更改后的设置并不能立即起效，需要先进行如下操作：
\begin{enumerate}
	\item 清除缓存。命令为：
	\begin{lstlisting}
	 git rm -r --cached .
	\end{lstlisting}
	\item 添加文件到仓库。
		\begin{lstlisting}
	 git add .
	\end{lstlisting}
\end{enumerate}
之后就可添加说明、推送。

\bibliography{../../bib/yangjh}
